/**
 * Axios封装
 */
import axios, { AxiosRequestConfig } from 'axios';
import qs from 'qs';
import * as HttpStatus from 'http-status-codes';
import router from '../router';
import { RequestFilter } from './request-filter';
import { message } from 'ant-design-vue';
import { ModalDialog } from '@/utils/modal-dialog';
import { Constant } from '@/constant';
import { JsCookies } from '@/utils/js-cookie';

export default class Axios {
  // axios 默认配置
  static defaults: AxiosRequestConfig = {
    baseURL: process.env.VUE_APP_API_BASE_URL,
    timeout: 0,
    headers: {
      'X-Requested-With': 'XMLHttpRequest',
      // 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
      'Content-Type': 'application/json'
    },
    paramsSerializer: function(params = {}) {
      return qs.stringify(params, {
        arrayFormat: 'repeat'
      });
    }
  };

  // axios 请求方法封装
  static get(url: string, params = {}): Promise<any> {
    return new Promise((resolve, reject) => {
      service({
        method: 'get',
        url,
        params: RequestFilter.filterEmptyParams(params),
        cancelToken: new CancelToken((c: any) => {
          cancel = c;
        })
      })
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  static downloadFile(url: string, params = {}): Promise<any> {
    return new Promise((resolve, reject) => {
      service({
        method: 'get',
        url,
        params: RequestFilter.filterEmptyParams(params),
        responseType: 'blob',
        cancelToken: new CancelToken((c: any) => {
          cancel = c;
        })
      })
        .then((res) => {
          resolve(res);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  static post(url: string, data = {}, params = {}): Promise<any> {
    return new Promise((resolve, reject) => {
      service({
        method: 'post',
        url,
        data: RequestFilter.filterEmptyParams(data),
        params: RequestFilter.filterEmptyParams(params),
        cancelToken: new CancelToken((c: any) => {
          cancel = c;
        })
      })
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  static uploadFile(url: string, formData = {}): Promise<any> {
    return new Promise((resolve, reject) => {
      service({
        method: 'post',
        url,
        data: formData,
        cancelToken: new CancelToken((c: any) => {
          cancel = c;
        })
      })
        .then((res) => {
          resolve(res);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  static put(url: string, data = {}, params = {}): Promise<any> {
    return new Promise((resolve, reject) => {
      service({
        method: 'put',
        url,
        data: RequestFilter.filterEmptyParams(data),
        params: RequestFilter.filterEmptyParams(params),
        cancelToken: new CancelToken((c: any) => {
          cancel = c;
        })
      })
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  static async head(url: string, params = {}): Promise<boolean> {
    let isExisted = false;

    await service({
      method: 'head',
      url,
      params: RequestFilter.filterEmptyParams(params),
      cancelToken: new CancelToken((c: any) => {
        cancel = c;
      })
    })
      .then((res) => {
        if (res.status === 200) {
          isExisted = true;
        }
      })
      .catch(() => {});

    return isExisted;
  }

  static delete(url: string, data = {}, params = {}): Promise<any> {
    return new Promise((resolve, reject) => {
      service({
        method: 'delete',
        url,
        data: RequestFilter.filterEmptyParams(data),
        params: RequestFilter.filterEmptyParams(params),
        cancelToken: new CancelToken((c: any) => {
          cancel = c;
        })
      })
        .then((res) => {
          resolve(res);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }
}

const service = axios.create(Axios.defaults);

/* 使用 axios-cancelToken 阻止重复提交 */
let cancel = {};
const pending: any = {};
const CancelToken: any = axios.CancelToken;

const removePending = (key: any, isRequest = false) => {
  if (pending[key] && isRequest) {
    pending[key]('duplicate request');
  }
  delete pending[key];
};
const getRequestIdentify = (config: any, isRequest = false) => {
  let url = config.url;
  if (isRequest) {
    url = config.baseURL + config.url.substring(1, config.url.length);
  }
  return config.method === 'get' ? encodeURIComponent(url + JSON.stringify(config.params)) : encodeURIComponent(config.url + JSON.stringify(config.data));
};

/* 请求拦截器 */
service.interceptors.request.use(
  (config) => {
    let requestData = getRequestIdentify(config, true);
    removePending(requestData, true);
    config.cancelToken = new CancelToken((c: any) => {
      pending[requestData] = c;
    });

    // 从cookie中获取最新的authorization
    config.headers.authorization = JsCookies.getCookie('authorization');

    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  (response) => {
    if (response.status === 200 || response.status === 201 || response.status === 204) {
      return Promise.resolve(response);
    } else {
      return Promise.reject(response);
    }
  },
  (error) => {
    if (error.response.config.method !== 'head' && error.response.status) {
      switch (error.response.status) {
        case HttpStatus.BAD_REQUEST:
          ModalDialog.showError('badRequest', error.response.data.message);
          break;
        case HttpStatus.UNAUTHORIZED:
          router.push({
            name: 'login'
          });
          break;
        case HttpStatus.FORBIDDEN:
          message.error(error.response.data.message, Constant.DURATION);
          break;
        case HttpStatus.NOT_FOUND:
          message.error(error.response.data.message, Constant.DURATION);
          break;
        case HttpStatus.PRECONDITION_FAILED:
          // router.push({});
          break;
        default:
          ModalDialog.showError('unknownError', error.response.data.message);
          break;
      }
    }
    console.table(error);
    return Promise.reject(error.response);
  }
);
